package study.tag;

import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.Assert;

import study.domain.attachment.Attachment;
import study.domain.attachment.AttachmentType;

import com.barney.support.util.ClasspathResourceUtils;
import com.barney.support.web.WebSearch;

/**
 * URL 태그
 *
 * <blockquote><pre>
 * <tt>applicationContext.xml</tt> 파일
 *
 * <tt>&lt;mvc:resources mapping="/resources-#{T(study.tag.UrlTag).VERSION}/**" location="/WEB-INF/resources/"/&gt;</tt>
 * </pre></blockquote>
 *
 * 참고: <a href="http://static.springsource.org/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-static-resources">Static Resources</a>
 *
 * @author Barney Kim
 */
public class UrlTag {

	/**
	 * 버전은 실행 일시로 <tt>MMddHHmmss</tt> 형식이다.
	 */
	public static final String VERSION;

	public static final String RESOURCE_PREFIX = "/resources";

	private static final String STATIC_SERVER_URLS_KEY = "static.server.urls";

	public static final String[] STATIC_SERVER_URLS;

	private static final String APPLICATION_PROPERTY_PATH = "application-properties.xml";

	private static final Properties APPLICATION_PROPERTIES = new Properties();

	static {
		loadProperties(APPLICATION_PROPERTIES, APPLICATION_PROPERTY_PATH);

		VERSION = populateVersion();
		STATIC_SERVER_URLS = populateStaticServerUrls();
	}

	private static void loadProperties(Properties properties, String resourcePath) {
		InputStream istream = null;
		try {
			istream = ClasspathResourceUtils.getResourceAsStream(resourcePath);
			properties.load(istream);
		} catch (Exception ex) {
			throw new RuntimeException(ex.getMessage(), ex);
		} finally {
			IOUtils.closeQuietly(istream);
		}
	}

	private static String populateVersion() {
		SimpleDateFormat sdf = new SimpleDateFormat("MMddHHmmss");
		return sdf.format(new Date());
	}

	private static String[] populateStaticServerUrls() {
		String str = APPLICATION_PROPERTIES.getProperty(STATIC_SERVER_URLS_KEY);
		if (str == null) {
			str = "";
		}
		return StringUtils.trim(str).split(",");
	}

	/**
	 * @return 버전을 반환한다.
	 */
	public static String getVersion() {
		return VERSION;
	}

	/**
	 * JavaScript URL을 반환한다.
	 *
	 * @param url
	 */
	public static String jsUrl(String url) {
		return resourceUrl(url);
	}

	/**
	 * JavaScript 라이브러리 URL을 반환한다.
	 *
	 * @param url
	 */
	public static String jsLibUrl(String url) {
		return resourceUrl(url);
	}

	/**
	 * CSS URL을 반환한다.
	 *
	 * @param url
	 */
	public static String cssUrl(String url) {
		return resourceUrl(url);
	}

	/**
	 * 이미지 URL을 반환한다.
	 *
	 * @param url
	 */
	public static String imgUrl(String url) {
		return resourceUrl(url);
	}

	/**
	 * resource URL을 반환한다.
	 *
	 * @param url
	 */
	public static String resourceUrl(String url) {
		Assert.hasText(url, "url을 지정해야 합니다.");
		return String.format("%s-%s%s", RESOURCE_PREFIX, VERSION, url);
	}

	/**
	 * resource URL을 반환한다.
	 *
	 * @param url
	 */
	public static String resourceUrlPostfix(final String url) {
		Assert.hasText(url, "url을 지정해야 합니다.");
		String s = url;
		if (s.indexOf("?") > 0) {
			s += "&amp;v=";
		} else {
			s += "?v=";
		}
		return String.format("%s%s%s", RESOURCE_PREFIX, s, VERSION);
	}

	public static String staticUrl(String url) {
		return staticUrl(url, true);
	}

	public static String staticUrl(String url, boolean withVersion) {
		Assert.hasText(url, "url을 지정해야 합니다.");
		int serverId = getLastChar(url) % STATIC_SERVER_URLS.length;
		if (withVersion) {
			return String.format("%s%s-%s%s", STATIC_SERVER_URLS[serverId], RESOURCE_PREFIX,
					VERSION, url);
		}
		return String.format("%s%s%s", STATIC_SERVER_URLS[serverId], RESOURCE_PREFIX, url);
	}

	private static char getLastChar(String url) {
		int idx = url.lastIndexOf(".");
		String str = url;
		if (idx > 0) {
			str = url.substring(0, idx);
		}
		return str.charAt(str.length() - 1);
	}

	/**
	 * 검색을 위한 URL을 반환한다.
	 *
	 * @param search
	 */
	public static String urlForSearch(WebSearch search) {
		return search.toUrl();
	}

	/**
	 * 검색을 위한 URL을 반환한다.
	 *
	 * @param search
	 */
	public static String urlWithSearch(String prefixURI, WebSearch search) {
		return search.toUrl(prefixURI);
	}

	/**
	 * 첨부 파일을 위한 URL
	 */
	public static String urlForAttachment(Attachment attachment) {
		return attachment.getUrl();
	}

	public static String urlForImageAttachment(Attachment attachment) {
		return attachment.getUrl(AttachmentType.ORIGINAL);
	}

	public static String urlForImageAttachmentSmall(Attachment attachment) {
		return attachment.getUrl(AttachmentType.IMAGE_SMALL);
	}

	public static String urlForImageAttachmentMedium(Attachment attachment) {
		return attachment.getUrl(AttachmentType.IMAGE_MEDIUM);
	}

	public static String urlForImageAttachmentLarge(Attachment attachment) {
		return attachment.getUrl(AttachmentType.IMAGE_LARGE);
	}
}
